 /*******************************************************************************
  * Copyright (c) 2000, 2006 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.update.internal.ui.model;

 import java.net.*;
 import java.util.Vector ;

 import org.eclipse.core.runtime.*;
 import org.eclipse.osgi.util.NLS;
 import org.eclipse.update.core.*;
 import org.eclipse.update.internal.ui.*;

 public class SiteBookmark extends NamedModelObject
                             implements ISiteAdapter {

     private static final long serialVersionUID = 1L;
     public static final String P_URL="p_url"; //$NON-NLS-1$
 public static final String P_TYPE="p_type"; //$NON-NLS-1$

     private URL url;
     transient private ISite site;
     transient private Vector catalog = new Vector ();
     transient private SiteCategory otherCategory;
     private boolean webBookmark;
     private boolean selected;
     private String [] ignoredCategories = new String [0];
     private boolean readOnly = false;
     private boolean local = false;
     private boolean unavailable = false;
     private String description;

     public SiteBookmark() {
     }
     
     public SiteBookmark(String name, URL url, boolean webBookmark) {
         this(name, url, webBookmark, false);
     }
     
     public SiteBookmark(String name, URL url, boolean webBookmark, boolean selected) {
         super(name);
         this.url = url;
         this.webBookmark = webBookmark;
         this.selected = selected;
     }

     public boolean equals(Object obj) {
         if (obj == this)
             return true;
         if (!(obj instanceof SiteBookmark))
             return false;
         SiteBookmark b = (SiteBookmark)obj;
         if (url == null)
             return false;
         return url.equals(b.url);
     }

     public int hashCode() {
         if (url == null)
             return super.hashCode();
         else
             return url.hashCode();
     }

     public void setSelected(boolean selected) {
         this.selected = selected;
     }
     
     public boolean isSelected() {
         return selected;
     }
     
     public String [] getIgnoredCategories() {
         return ignoredCategories;
     }
     
     public void setIgnoredCategories(String [] categories) {
         this.ignoredCategories = categories;
     }
     
     public void setWebBookmark(boolean value) {
         if (isLocal()) return;
         this.webBookmark = value;
         notifyObjectChanged(P_TYPE);
     }
     
     public boolean isWebBookmark() {
         return webBookmark;
     }
     
     public URL getURL() {
         return url;
     }


     public void setURL(URL url) {
         this.url = url;
         site = null;
         notifyObjectChanged(P_URL);
     }
     
     public ISite getSite(IProgressMonitor monitor) {
         return getSite(true, monitor);
     }
     
     public ISite getSite(boolean showDialogIfFailed, IProgressMonitor monitor) {
         if (site==null) {
             try {
                 connect(monitor);
             }
             catch (CoreException e) {
                 UpdateUI.logException(e, showDialogIfFailed);
             }
         }
         return site;
     }
     
     public boolean isSiteConnected() {
         return site!=null;
     }
     
     public void connect(IProgressMonitor monitor) throws CoreException {
         connect(true, monitor);
     }
     
     public void connect(boolean useCache, IProgressMonitor monitor) throws CoreException {
         try {
             if (monitor==null) monitor = new NullProgressMonitor();
             monitor.beginTask("", 2); //$NON-NLS-1$
 monitor.subTask(NLS.bind(UpdateUIMessages.SiteBookmark_connecting, url.toString()));
             site = SiteManager.getSite(url, useCache, new SubProgressMonitor(monitor, 1));
             if (site!=null) {
                 createCatalog(new SubProgressMonitor(monitor, 1));
                 unavailable = false;
             } else {
                 catalog = new Vector ();
                 unavailable = true;
             }
         } catch (CoreException e) {
             unavailable = true;
             throw e;
         }
     }
     
     public boolean isUnavailable() {
         return unavailable;
     }
     
     public void setUnavailable(boolean value) {
         unavailable = value;
     }
     
     private void createCatalog(IProgressMonitor monitor) {
         catalog = new Vector ();
         otherCategory = new SiteCategory(this, null, null);
         // Add all the categories
 ICategory [] categories = site.getCategories();
         
         ISiteFeatureReference [] featureRefs;
         featureRefs = site.getRawFeatureReferences();
         
         monitor.beginTask("", featureRefs.length + categories.length); //$NON-NLS-1$

         for (int i=0; i<categories.length; i++) {
             ICategory category = categories[i];
             addCategoryToCatalog(category);
             monitor.worked(1);
         }
         // Add features to categories

         for (int i=0; i<featureRefs.length; i++) {
             ISiteFeatureReference featureRef = featureRefs[i];
             addFeatureToCatalog(featureRef);
             monitor.worked(1);
         }
         if (otherCategory.getChildCount()>0)
            catalog.add(otherCategory);
         
         // set the site description
 IURLEntry descURL = site.getDescription();
         if (descURL != null)
             description = descURL.getAnnotation();
     }

     public Object [] getCatalog(boolean withCategories, IProgressMonitor monitor) {
         if (withCategories)
             return catalog.toArray();
         else {
             // Make a flat catalog
 Vector flatCatalog = new Vector ();
             for (int i=0; i<catalog.size(); i++) {
                 SiteCategory category = (SiteCategory)catalog.get(i);
                 category.addFeaturesTo(flatCatalog);
             }
             return flatCatalog.toArray();
         }
     }
     
     private void addCategoryToCatalog(ICategory category) {
         String name = category.getName();
         int loc = name.indexOf('/');
         if (loc == -1) {
             // first level
 catalog.add(new SiteCategory(this, name, category));
         }
         else {
             IPath path = new Path(name);
             name = path.lastSegment().toString();
             path = path.removeLastSegments(1);
             SiteCategory parentCategory = findCategory(path, catalog.toArray());
             if (parentCategory!=null) {
                 parentCategory.add(new SiteCategory(this, name, category));
             }
         }
     }
     private void addFeatureToCatalog(ISiteFeatureReference feature) {
         ICategory [] categories = feature.getCategories();
         boolean orphan = true;

         for (int i=0; i<categories.length; i++) {
             ICategory category = categories[i];
             String name = category.getName();
             IPath path = new Path(name);
             SiteCategory parentCategory = findCategory(path, catalog.toArray());
             if (parentCategory!=null) {
                 parentCategory.add(new FeatureReferenceAdapter(feature));
                 orphan = false;
             }
         }
         if (orphan)
             otherCategory.add(new FeatureReferenceAdapter(feature));
     }
     
     private SiteCategory findCategory(IPath path, Object [] children) {
         for (int i=0; i<children.length; i++) {
             Object child = children[i];
             if (child instanceof SiteCategory) {
                 SiteCategory sc = (SiteCategory)child;
                 if (sc.getName().equals(path.segment(0))) {
                    if (path.segmentCount()==1) return sc;
                     else {
                         path = path.removeFirstSegments(1);
                         return findCategory(path, sc.getChildren());
                     }
                 }
             }
         }
         return null;
     }
     
     /**
      * @see ISiteAdapter#getLabel()
      */
     public String getLabel() {
         return getName();
     }
     
     public void setReadOnly(boolean readOnly) {
         this.readOnly = readOnly;
     }
     
     public boolean isReadOnly() {
         return readOnly;
     }
     
     public void setLocal(boolean local) {
         this.local = local;
     }
     
     public boolean isLocal() {
         return local;
     }

     /**
      * @param description The description to set.
      */
     public void setDescription(String description) {
         this.description = description;
     }

     /**
      * @return Returns the description.
      */
     public String getDescription() {
         if (description == null && isSiteConnected()) {
             IURLEntry descURL = site.getDescription();
             if (descURL != null)
                 description = descURL.getAnnotation();
         }
         return description;
     }
 }

